Skip to content

feat: grammar-based value completion#494

Merged
SJrX merged 2 commits into
242.xfrom
grammar-value-completion
Jun 26, 2026
Merged

feat: grammar-based value completion#494
SJrX merged 2 commits into
242.xfrom
grammar-value-completion

Conversation

@SJrX

@SJrX SJrX commented Jun 26, 2026

Copy link
Copy Markdown
Owner

What

Grammar-driven value completion for GrammarOptionValue options. The frontier we built for error localization (the Stuck/expected set, already on 242.x) answers exactly what completion needs — "what was expected at this offset?" is the same question as "what could come next here?".

Adds Combinator.nextTokenChoices(prefix) (pure Kotlin, no IntelliJ types): parse the typed prefix, read the Stuck values whose offset is the end of the prefix, and collect the enumerable choices of the terminals expected there (LiteralChoiceTerminal / FlexibleLiteralChoiceTerminal; numbers/regexes/whitespace/EOF contribute nothing to suggest).

Gating (important)

Wired into UnitFileValueCompletionContributor behind:

if (ExperimentalSettings.getInstance(property.project).state.useGrammarParseEngine &&
    validator is GrammarOptionValue) {
  addGrammarCompletions(...); return
}
// otherwise: the existing completion path, untouched

This is new behaviour, so it's gated behind the experimental flag — with the flag off, completion behaves exactly as before. (Correctness fixes to existing validators stay default; new behaviours opt in.)

Two behaviours

  • Partial token: sets the prefix matcher so RestrictAddressFamilies=AF_IN⎮ offers AF_INET / AF_INET6 (rather than the lenient terminal treating AF_IN as a finished token).
  • Forced-separator chaining: on accepting a choice, walk the grammar forward and auto-insert any single forced punctuation separator (e.g. homehome=), then re-open completion — never auto-inserting a content token the user should pick.

Scope

Bundles stacked PRs #477 (completion) + #478 (forced-separator chaining), re-cut against current 242.x. The AF-family completion works because #492's enumerated AF validator is now on 242.x.

Verification

./gradlew test and ./gradlew test -Dsystemd.unit.grammarParseEngine=true both pass. Tests enable the flag and reset it in tearDown so it doesn't leak into the shared light-test project.

🤖 Generated with Claude Code

The frontier built for error localization answers exactly the question
completion needs — "what was expected at this offset?" is "what could come next
here?". Adds Combinator.nextTokenChoices(prefix), which reads the Stuck values at
the end of the typed prefix and collects the enumerable choices expected there
(literal / flexible-literal terminals; numbers/regexes/whitespace contribute
nothing to suggest).

Wires it into UnitFileValueCompletionContributor, gated behind
ExperimentalSettings.useGrammarParseEngine AND validator is GrammarOptionValue:
with the flag off the existing completion path is untouched. Two behaviours:
  - completing a partial token (sets the prefix matcher so "AF_IN" -> AF_INET/6)
  - chaining through forced separators on accept (e.g. accepting "home" inserts
    "home=" and re-opens completion, never auto-inserting a content token)

Bundles the stacked PRs #477 (completion) and #478 (forced-separator chaining),
re-cut against current 242.x. New behaviour, so flag-gated; correctness of
existing validators is unchanged. Tests enable the flag and reset it in tearDown
to avoid leaking into the shared light-test project.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@SJrX SJrX changed the title feat: grammar-based value completion behind the experimental flag feat: grammar-based value completion Jun 26, 2026
The completion bundle tested the flag-on behaviours but not two things worth
guaranteeing: that grammar completion stays suppressed when the experimental
engine is off (the gating contract), and that a non-enumerable next token
(number/regex) offers nothing rather than crashing or suggesting junk.

- GrammarValueCompletionTest.testFlagOffOffersNoGrammarCompletions: flag off, the
  AF_IN partial yields no AF_* names (the flag-on path's suggestions are absent).
- NextTokenChoicesTest.testNonEnumerableNextTokenOffersNothing: an IntegerTerminal
  port grammar returns an empty choice set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Unit Test Results (grammar engine false)

1 152 tests   1 152 ✅  51s ⏱️
  302 suites      0 💤
  302 files        0 ❌

Results for commit da375e2.

@github-actions

Copy link
Copy Markdown

Unit Test Results (grammar engine true)

1 152 tests   1 152 ✅  50s ⏱️
  302 suites      0 💤
  302 files        0 ❌

Results for commit da375e2.

@SJrX SJrX merged commit 1e3ea0d into 242.x Jun 26, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant